package sg.edu.nus.iss.billing.datastore;

import java.lang.reflect.Type;
import java.util.List;

import sg.edu.nus.iss.billing.entity.BaseEntity;
import sg.edu.nus.iss.billing.exception.DataStoreException;

/**
 * <h2>This interface define the way to store object and load object from data file</h2>
 * Only the child class of BaseEntity can be stored/read to/from data files through this interface</br>
 * All the objects will automatically generate an id to identify it in storage. 
 * 
 * @author Wang DaYong
 * 
 */
public interface IDataStore {

	/**
	 * To load object from data file by the specified type and primary key ID
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param type
	 *            The type to load
	 * @param id
	 *            The id of object
	 * @return <T extends BaseEntity> Child of BaseEntity, if no record found
	 *         will return null
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> T loadObjectByID(Type type, String id) throws DataStoreException;

	/**
	 * To load all the objects of specified type from data file And refer to
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param type
	 *            The type to load
	 * @param id
	 *            The id of object
	 * @return List<T extends BaseEntity> List of BaseEntity's child class, , if
	 *         no record found will return null
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> List<T> loadObjectsByType(Type type) throws DataStoreException;

	/**
	 * To batch load objects by specified type and list of IDs And refer to
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param type
	 *            The type to load
	 * @param id
	 *            The id of object
	 * @return List<T extends BaseEntity> List of BaseEntity's child class, , if
	 *         no record found will return null
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> List<T> loadObjectsByIDs(Type type, String... id) throws DataStoreException;

	/**
	 * To batch load object by defined type and selector. selector is using for
	 * searching on non-id field of the object. Please refer to {@link ISelector}
	 * for more details.
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param type
	 *            The type to load
	 * @param selector
	 *            The selector on the return list, refer to {@link ISelector}
	 * @return
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> List<T> loadObjectsBySelector(Type type, ISelector selector) throws DataStoreException;

	/**
	 * To save object to data file, if the object has existed(same id found) in
	 * data file, will do updating, else will do insert. And if the ID value of
	 * object is null or empty system will automatic assign an unique id to it.
	 * Note: in current version, avoid setId manually, all id will be generated by
	 * program, or will throw DataStoreException</br>
	 * All update will check the version, if others update the same record(s), 
	 * will cause DataStoreException
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param object
	 *            The instance of subclass of BaseEntity
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> void saveObject(T object) throws DataStoreException;

	/**
	 * Same operation as saveObject(T object), but batch saving
	 * 
	 * All update will check the version, if others update the same record(s), 
	 * will cause DataStoreException
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param object
	 *            The instance of subclass of BaseEntity
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> void saveObjects(List<T> list) throws DataStoreException;

	/**
	 * Remove instance from data file permanently
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param object
	 *            The instance of subclass of BaseEntity
	 * @param id
	 *            The id of object
	 * @throws DataStoreException
	 *             , if the id not found in data file, will throw
	 *             NoRecordFoundException which is the subclass of
	 *             DataStoreException
	 */
	public <T extends BaseEntity> void deleteObjectByID(Type type, String id) throws DataStoreException;

	/**
	 * Batch remove instances from data file permanently
	 * 
	 * @param <T>
	 *            Subclass of BaseEntity
	 * @param list
	 *            List of instances of <T extends BaseEntity>
	 * @throws DataStoreException
	 */
	public <T extends BaseEntity> void deleteObjects(List<T> list) throws DataStoreException;
	
	
	/**
	 * Delete objects by type permanently
	 * @param type
	 * @throws DataStoreException
	 */
	public void deleteObjectsByType(Type type) throws DataStoreException;

	
	/**
	 * obtain the transaction, if the implementation does not support transaction will cause
	 * DataStoreException
	 * 
	 * @return Transaction
	 * @throws DataStoreException
	 */
	public Transaction getTransaction() throws DataStoreException;
}
